﻿using System;
using System.Collections.Generic;

namespace PusherClient
{
    internal class Channel : IChannel, IDisposable
    {
        private readonly string _channelName;
        private readonly Connection _connection;
        private readonly Dictionary<string, List<Action<EventData>>> _events = new Dictionary<string, List<Action<EventData>>>();

        public Channel(string channelName, Connection connection)
        {
            _channelName = channelName;
            _connection = connection;
            this._connection.MessageReceived += MessageReceived;
            this._connection.Connected += Connected;

            if (this._connection.State == ConnectionState.Connected)
                Subscribe();
        }

        private void Connected(object sender, EventArgs e)
        {
            Subscribe();
        }

        private void MessageReceived(object sender, MessageEventArgs e)
        {
            if (e.Message.Channel != this._channelName)
                return;

            if (this._events.ContainsKey(e.Message.EventType))
            {
                EventData eventData = new EventData(this._channelName, e.Message.EventType, e.Message.Data.ToString());
                foreach (Action<EventData> action in _events[e.Message.EventType])
                {
                    action.Invoke(eventData);
                }
            }
        }

        private void Subscribe()
        {
            PusherSubscribeMessage subscribeMessage = new PusherSubscribeMessage(this._channelName);

            this._connection.Send(subscribeMessage);
        }

        private void Unsubscribe()
        {
            PusherUnsubscribeMessage subscribeMessage = new PusherUnsubscribeMessage(this._channelName);

            this._connection.Send(subscribeMessage);
        }

        public void Bind(string eventName, Action<EventData> action)
        {
            if (!this._events.ContainsKey(eventName))
                _events.Add(eventName, new List<Action<EventData>>());

            this._events[eventName].Add(action);
        }

        public void UnBind(string eventName)
        {
            if (this._events.ContainsKey(eventName))
                this._events[eventName] = new List<Action<EventData>>();
        }

        public void Dispose()
        {
            this.Unsubscribe();
            this._events.Clear();

            this._connection.MessageReceived -= MessageReceived;
            this._connection.Connected -= Connected;
        }
    }
}
